﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Shoozla.DataModel.Helper;
using System.Windows.Forms;
using System.Resources;

namespace Shoozla.DataModel
{
    //it is a cache
    /// <summary>
    /// Rappresent a Memory cache that for each entry download the Image and store it in memory
    /// </summary>
    public class InternetCoverStorage : ICoverStorage
    {

        private CancellationTokenSource _cancelTokenSource;
        public CancellationTokenSource CancelTokenSource
        {
            get { return _cancelTokenSource; }
            set { _cancelTokenSource = value; _parallelSettings.CancellationToken = value.Token; }
        }

        public ObservableCollection<CoverThumb> CoverThumbnails
        {
            get
            {
                //returning a new collection with all the covers found (key == url)
                ObservableCollection<CoverThumb> coverThumbs = new ObservableCollection<CoverThumb>();
                foreach (KeyValuePair<string, InternalThumbObject> coverItem in _covers)
                {
                    if (coverItem.Value != null)
                    {
                        var thumb = new CoverThumb(((InternalThumbObject)coverItem.Value).DisplayName, new Uri(coverItem.Key), coverItem.Value.Method);
                        thumb.IsSelected = true;
                        coverThumbs.Add(thumb);
                    }
                }
                return coverThumbs;

            }
        }

        private ConcurrentDictionary<String, InternalThumbObject> _covers;
        private ParallelOptions _parallelSettings;

        public event ImageDownloadedDelegate ImageDownloaded;
        public delegate void ImageDownloadedDelegate(Image image);

        public bool RemoveCover(string uri)
        {
            InternalThumbObject oldValue;
            return _covers.TryRemove(uri.ToLowerInvariant(), out oldValue);
        }

        public InternetCoverStorage(CancellationTokenSource token)
        {
            _covers = new ConcurrentDictionary<String, InternalThumbObject>();
            _parallelSettings = new ParallelOptions();
            CancelTokenSource = token;
        }

        private void DownloadImageFromInternet(KeyValuePair<string, InternalThumbObject> item)
        {
            _covers.AddOrUpdate(item.Key, (k) => DownloadImage(k, item.Value.DisplayName, item.Value.Method), (key, oldValue) => DownloadImage(key, item.Value.DisplayName, item.Value.Method));
        }

        private InternalThumbObject DownloadImage(string uri, string displayName, SearchMethod method)
        {
            try
            {
                WebRequest req = WebRequest.Create(uri);
                WebResponse response = req.GetResponse();
                Stream stream = response.GetResponseStream();
                Image im = Image.FromStream(stream);
                Trace.WriteLine("[IMAGE] Download Image: " + uri);
                if (ImageDownloaded != null)
                {
                    foreach (Delegate d in ImageDownloaded.GetInvocationList())
                    {
                        d.DynamicInvoke(im); //updating the UI
                    }
                }

                return new InternalThumbObject(displayName, im, method);

            }
            catch (Exception e)
            {
                Trace.WriteLine("[ERROR] InternetCoverStorage: DownloadImage: " + e.Message);
                return null;
            }
        }

        public bool ContainsCover(string uri)
        {
            return _covers.ContainsKey(uri.ToLowerInvariant());
        }

        public InternalThumbObject this[string uri]
        {
            get
            { return (InternalThumbObject)_covers[uri.ToLowerInvariant()]; }
        }

        /// <summary>
        /// synchronous download of all images
        /// </summary>
        public void DownloadImages()
        {
            try
            {
                //Task backgroundDownloadTask = Task.Factory.StartNew(() =>
                //           {
                _parallelSettings.MaxDegreeOfParallelism = ThreadHelper.CalculateTreads(_covers.Count, ThreadingFactorEnum.Maximum);
                Parallel.ForEach(_covers, _parallelSettings, (item) => DownloadImageFromInternet(item));
                //           }, CancelToken);

                //backgroundDownloadTask.Wait(CancelToken);
            }
            catch (OperationCanceledException ae)
            {
                return; //search cancelled
            }
        }

        /// <summary>
        /// Async method to trigger the download of a cover
        /// </summary>
        public void AddCoverToStorage(String coverUri, string displayName, SearchMethod method)
        {
            Task.Factory.StartNew((Action)(() =>
            {
                lock (this)
                {
                    try
                    {
                        coverUri = coverUri.ToLowerInvariant();

                        if (!_covers.ContainsKey(coverUri))
                        {
                            _covers.GetOrAdd(coverUri, (InternalThumbObject)new InternalThumbObject(displayName, null, method)); //override
                            //now download the image asynchronously
                            //Action downloadImageAction = new Action(
                            //     () =>
                            //     {
                                     _covers.AddOrUpdate(coverUri, (key) => DownloadImage(coverUri, displayName, method), (key, oldValue) => DownloadImage(key, displayName, method));
                                     //       _numActiveDownload--;
                            //     });

                            ////_numActiveDownload++;
                            ////Parallel.Invoke(
                            //Task downloadImageTask = Task.Factory.StartNew(downloadImageAction, CancelTokenSource.Token);
                            ////  _tasks.Add(downloadImageTask);
                        }
                        else
                        {
                            //cover already download, but let's trigger the event to display the UI
                            if (ImageDownloaded != null)
                            {
                                foreach (Delegate d in ImageDownloaded.GetInvocationList())
                                {
                                    d.DynamicInvoke(_covers[coverUri]); //updating the UI
                                }
                            }

                            Trace.WriteLine("[IMAGE] Cache: " + coverUri);
                        }


                    }
                    catch (AggregateException ae)
                    {
                        //user cancelled the operation, silent returning

                    }
                    catch (Exception e)
                    {
                        Trace.WriteLine("[ERROR] InternetCoverStorage: AddCoverToStorage: " + e.Message);

                    }
                }
            }),TaskCreationOptions.LongRunning);
        }

        public void LoadFromStorage(string filename)
        {
            ; ;
        }

        public void SaveToStorage(string filename)
        {
            ; ;
        }

        public ObservableCollection<Mp3File> GetAllCovers()
        {
            return null;
        }

        public void Reset()
        {
            _covers.Clear();
        }
    }
}

